package cc.iotkit.screen;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.annotations.ApiModelProperty;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

public class HuToolExcelUtils {
    private static Logger log = LoggerFactory.getLogger(HuToolExcelUtils.class);
    /**
     * <p>
     * 将数据生成Excel（xlsx格式）直接输出到response.getOutputStream()流
     * Excel表头会根据泛型中每个字段的Swagger注解@ApiModelProperty的value生成对应的中文
     *      1) 如果某字段没有标注@ApiModelProperty,则该字段不会被写入Excel
     *      2) 如果泛型中没有任何字段标注@ApiModelProperty,则默认全部字段导出,表头为字段名
     *  注意事项：
     *      hutool-poi:4.6.17 在这个版本中发现LocalDateTime类型的导出后格式为：-> 2023-04-28T16:06:00
     *      单元格格式为常规，所以日期类型的字段建议使用{@link java.util.Date},这样单元格格式是日期
     *      不知道新版hutool-poi中是否存在此问题？<br>
     * </p>
     * @param data      被导出的Excel数据
     * @param fileName  文件名(请不要带后缀)
     * @param <T>
     * @return          导出结果 成功=true;失败=false;
     */
    public static  <T> boolean list2xlsx(List<T> data, String fileName) throws IOException {
        if (data == null || data.isEmpty()){
            log.info("Excel导出数据为空");
            return false;
        }
        T t = data.get(0);
        if (t == null){
            log.info("Excel导出数据异常,index(0) = null");
            return false;
        }
        Class<?> aClass = t.getClass();
        Field[] declaredFields = aClass.getDeclaredFields();
        Map<String, String> headerAlias = new LinkedHashMap<>();
        for (Field field : declaredFields) {
            ExcelProperty annotation = field.getAnnotation(ExcelProperty.class);
            if (annotation != null ){
                headerAlias.put(field.getName(),annotation.value()[0]);
            }
        }
        ExcelWriter excelWriter = ExcelUtil.getWriter(true);
        if ( ! headerAlias.isEmpty()) {
            excelWriter.setHeaderAlias(headerAlias);
            excelWriter.setOnlyAlias(true);
        }
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletResponse response = Objects.requireNonNull(servletRequestAttributes).getResponse();

        excelWriter.write(data, true);
        try {
            //response为HttpServletResponse对象
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
//test.xls是弹出下载对话框的文件名，不能为中文，中文请自行编码
            response.setHeader("Content-Disposition","attachment;filename=test.xls");
            //Objects.requireNonNull(response).setHeader(HttpHeaders.CONTENT_DISPOSITION, URLUtil.encode("attachment;fileName="+fileName+".xlsx"));
            excelWriter.flush(response.getOutputStream(), true);
            return true;
        } catch (IOException e) {
            log.error("excel导出失败 inputParams:{} and errorMessage:{}",data,e.getMessage(),e);
        }finally {
            excelWriter.close();
            IoUtil.close(response.getOutputStream());
        }
        return false;
    }

    public static  <T> void exportListToExcel(List<T> dataList, String fileName) throws IOException {
        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet("Data");

        // 创建表头
        Row header = sheet.createRow(0);
        Field[] fields = dataList.get(0).getClass().getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            header.createCell(i).setCellValue(fields[i].getName());
        }

        // 填充数据
        int rowIndex = 1;
        for (T data : dataList) {
            Row row = sheet.createRow(rowIndex++);
            int cellIndex = 0;
            for (Field field : fields) {
                field.setAccessible(true);
                try {
                    row.createCell(cellIndex++).setCellValue(field.get(data)==null?"":field.get(data).toString());
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }


        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletResponse response = Objects.requireNonNull(servletRequestAttributes).getResponse();
        HttpServletRequest request=Objects.requireNonNull(servletRequestAttributes).getRequest();
        response.setContentType("application/xlsx");
        //设置保存文件名，将inline改为attachment则直接提示下载
        response.setHeader("Content-Disposition", "attachment; filename="+new String(fileName.getBytes("gb2312"), "ISO8859-1")+".xlsx");

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        workbook.write(outputStream);
        byte[] bytes = outputStream.toByteArray();
        ServletOutputStream outStream = response.getOutputStream();

        ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
        if(inputStream!=null){
            byte[] results = FileCopyUtils.copyToByteArray(inputStream);
            outputStream.write(bytes,0,results.length);
            outputStream.flush();
        }


       /* outStream.write(bytes,0,bytes.length);
        outStream.flush();
        outStream.close();*/


    }

}
